/*
	Copyright 2012 Google Inc. All Rights Reserved.

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

	    http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.package main
*/

package common

import (
	"gominion_server/gominionbase"
	"fmt"
	"net"
	"encoding/binary"
	"encoding/json"
	"io"
)

type Type byte

const (
	BASE_MESSAGE_RESERVED Type = iota
	CONNECT
	GET_STATUS
	STATUS
	JOIN_GAME
	CREATE_GAME
)

type Message interface {
	Message()
}

type BaseMessage struct {
	MessageType Type
}

func (b BaseMessage) Message() {
}

type Connect struct {
	BaseMessage
	Nickname string
	Status string
}

type GetStatus struct {
	BaseMessage
}

type Status struct {
	BaseMessage
	Status string
}

type JoinGame struct {
	BaseMessage
	GameName string
}

type CreateGame struct {
	JoinGame
	VetoMode bool
	NotCards []string
	Restrictions []string
}

type BadMessageError struct {
	message string
}

func (b BadMessageError) Error() string {
	return fmt.Sprintf("The message %v had invalid type.",b.message)
}

func ReadJSONMessage(conn net.Conn) ([]byte, error) {
	var messageLength int32
	readErr := binary.Read(conn, binary.BigEndian, &messageLength)
	if readErr != nil {
		return nil, readErr
	}
	message := make([]byte,messageLength)
	_, readErr = conn.Read(message)
	if readErr != nil {
		fmt.Println(readErr.Error())
	}
	return message, nil
}

func ReadMessage(conn net.Conn) (Message, error) {
	message, readErr := ReadJSONMessage(conn)
	if readErr != nil {
		return nil, readErr
	}
	var b BaseMessage
	json.Unmarshal(message,&b)
	switch b.MessageType {
		case CONNECT: {
			var m Connect
			json.Unmarshal(message,&m)
			return m,nil
		}
		case GET_STATUS: {
			var m GetStatus
			json.Unmarshal(message,&m)
			return m,nil
		}
		case STATUS: {
			var m Status
			json.Unmarshal(message,&m)
			return m,nil
		}
		case JOIN_GAME: {
			var m JoinGame
			json.Unmarshal(message,&m)
			return m,nil
		}
		case CREATE_GAME: {
			var m CreateGame
			json.Unmarshal(message,&m)
			return m,nil
		}
		default: {
		}
	}
	return nil,BadMessageError{string(message)}
}

func ConnectionLoop(conn net.Conn, player gominionbase.Player) {
	for {
		message, readErr := ReadMessage(conn)
		if readErr != nil {
			if readErr == io.EOF {
				fmt.Println("Connection terminated.")
				return
			}
			fmt.Println(readErr.Error())
		}
		_ = message
	}
}
